const {
  registerFont,
  createCanvas,
  loadImage
} = require('canvas');
const fs = require('fs')
registerFont(__dirname + '/msyh.ttf', {
  family: 'Microsoft YaHei'
});

var getRandomColor = function () {
  return '#' + ('00000' + (Math.random() * 0x1000000 << 0).toString(16)).substr(-6);
}
const colors = ['#5f3c23', '#412f1f', '#973c3f', '#aa2116', '#d64f44', '#840228', '#892f1b', '#c37e00', '#b36d41', '#f36c21', '#596032', '#1b315e', '#2468a2', '#008792', '#80752c', '#6c4c49', '#7d5886', '#401c44', '#d93a49', '#225a1f', '#4f5555', '#444693', '#2a5caa', '#464547']

function strokeRoundRect(cxt, x, y, width, height, radius,/*optional*/lineWidth,/*optional*/strokeColor) {
  //圆的直径必然要小于矩形的宽高          
  if (2 * radius > width || 2 * radius > height) { return false; }

  cxt.save();
  cxt.translate(x, y);
  //绘制圆角矩形的各个边  
  cxt.lineWidth = "1";
  drawRoundRectPath(cxt, width, height, radius);
  //cxt.lineWidth = 1;//若是给定了值就用给定的值否则给予默认值2  
  //cxt.strokeStyle = strokeColor || "#000";
  cxt.stroke();
  cxt.restore();
}

function drawRoundRectPath(cxt, width, height, radius) {
  cxt.beginPath(0);
  //从右下角顺时针绘制，弧度从0到1/2PI  
  cxt.arc(width - radius, height - radius, radius, 0, Math.PI / 2);

  //矩形下边线  
  cxt.lineTo(radius, height);

  //左下角圆弧，弧度从1/2PI到PI  
  cxt.arc(radius, height - radius, radius, Math.PI / 2, Math.PI);

  //矩形左边线  
  cxt.lineTo(0, radius);

  //左上角圆弧，弧度从PI到3/2PI  
  cxt.arc(radius, radius, radius, Math.PI, Math.PI * 3 / 2);

  //上边线  
  cxt.lineTo(width - radius, 0);

  //右上角圆弧  
  cxt.arc(width - radius, radius, radius, Math.PI * 3 / 2, Math.PI * 2);

  //右边线  
  cxt.lineTo(width, height - radius);
  cxt.closePath();
}

class Treechart {
  constructor() {
    this.canvasWidth = 0;
    this.canvasHeight = 0;
    this.color = '#5c4177';
    this.data = [];
    this.dataOptions = {};
  }
  setData(data) {
    this.data = data;
    //fs.writeFileSync(__dirname + '/data.txt', JSON.stringify(this.data));
  }
  setDataOptions(options) {
    this.dataOptions = options;
  }
  calcRange() {
    let maxWidth = 0;
    let minHeight = 0;
    for (let i = 0; i < this.data.length; i++) {
      const item = this.data[i];
      if (item instanceof Array) {
        let itemHeight = 12;
        let childHeight = itemHeight;
        if (item.length % 2 == 0) {
          childHeight = item.length * (16 + 4 + 2 + 6) + 30;
        } else {
          childHeight = item.length * (12 + 4 + 2 + 6) + 20;
        }
        if (childHeight > itemHeight) {
          itemHeight = childHeight;
        }
        minHeight += itemHeight;
        for (let j = 0; j < item.length; j++) {
          const elem = item[j];
          let eWidth = 42 + 6 + 2 + 18 + 2 + 10 + elem.org_fac.length * 12 + 10 + 2 + 6 + 25 + elem.sec_name.length * 12 + 25 + elem.org.length * 12 + 6 + 12 * 8 * 2;
          if (eWidth > maxWidth) {
            maxWidth = eWidth;
          }
        }
      }
    }
    this.canvasWidth = 10 * 2 + maxWidth;
    this.canvasHeight = 10 * 2 + minHeight;
  }
  draw() {
    if (this.data instanceof Array && this.data.length > 0) {
      const colorSet = colors.sort(function () {
        return Math.random() > .5 ? -1 : 1;
      });
      this.calcRange();
      this.canvas = createCanvas(this.canvasWidth, this.canvasHeight);
      const ctx = this.canvas.getContext('2d');
      // draw title;
      ctx.beginPath();
      ctx.lineWidth = "2";
      ctx.strokeStyle = this.color;
      ctx.lineJoin = "round";
      strokeRoundRect(ctx, 10, this.canvasHeight / 2 - 166 / 2, 40, 166, 7)
      //ctx.rect(10, this.canvasHeight / 2 - 166 / 2, 40, 166);
      ctx.stroke();
      ctx.save();
      ctx.font = '16px "Microsoft YaHei"';
      let title = this.dataOptions.title ;
      let dataParameters = this.dataOptions.dataParameters;
      let y = this.canvasHeight / 2 - 166 / 2 + 30;
      title.split('').forEach((item, index) => {
        ctx.fillText(item, 12 + 10, y);
        y += 16 + 2;
      })
      //this.fillTextVertical(ctx, '知名游资龙虎榜', 22 + 14, this.canvasHeight / 2 - 166 / 2 + 22);
      ctx.restore();
      ctx.beginPath();
      ctx.moveTo(50, this.canvasHeight / 2);
      ctx.lineTo(58, this.canvasHeight / 2);
      ctx.stroke();
      let itemY = 20;
      let firstItemMiddleHeight = 0;
      let lastItemMiddleHeight = 0;
      for (let i = 0; i < this.data.length; i++) {
        const item = this.data[i];
        if (item instanceof Array) {
          let itemHeight = 14 + 10 * 2;
          let childHeight = itemHeight;
          if (item.length % 2 == 0) {
            childHeight = item.length * (16 + 4 + 2 + 6) + 30;
          } else {
            childHeight = item.length * (12 + 4 + 2 + 6) + 20;
          }
          if (childHeight > itemHeight) {
            itemHeight = childHeight;
          }
          //itemHeight += 2 * 2;
          ctx.save();
          let color = this.color;
          if (i < colorSet.length) {
            color = colorSet[i];
          } else {
            color = getRandomColor();
          }
          ctx.strokeStyle = color;
          ctx.fillStyle = color;
          ctx.font = '13px "Microsoft YaHei"';
          ctx.beginPath();
          ctx.moveTo(58, itemHeight / 2 + itemY);
          ctx.lineTo(58 + 18, itemHeight / 2 + itemY);
          if (i == 0) {
            firstItemMiddleHeight = itemHeight / 2 + itemY;
          }
          if (i == this.data.length - 1) {
            lastItemMiddleHeight = itemHeight / 2 + itemY;
          }
          ctx.stroke();
          strokeRoundRect(ctx, 58 + 18, itemHeight/2 + itemY - 16, ctx.measureText(item[0][dataParameters[0].name]).width + 20, 34, 7)
          //ctx.rect(58 + 18, itemHeight / 2 + itemY - 16, ctx.measureText(item[0][dataParameters[0].name]).width + 20, 34);
          ctx.stroke();
          ctx.fillText(item[0][dataParameters[0].name], 58 + 18 + 10, itemHeight / 2 + itemY - 16 + 22);

          //ctx.moveTo(58 + 18 + ctx.measureText(item[0][dataParameters[0].name]).width + 20, itemHeight / 2 + itemY);
          //ctx.lineTo(58 + 18 + ctx.measureText(item[0][dataParameters[0].name]).width + 20 + 12, itemHeight / 2 + itemY);
          ctx.stroke();

          ctx.restore();
          let itemLength = item.length;
          let half = Math.floor(itemLength / 2);
          let even = itemLength % 2 == 0 ? true : false;
          for (let j = 0; j < item.length; j++) {
            const elem = item[j];
            ctx.save();
            ctx.strokeStyle = color;
            ctx.fillStyle = color;
            ctx.font = '11px "Microsoft YaHei"';
            ctx.beginPath();
            //ctx.moveTo(58 + 18 + ctx.measureText(item[0][dataParameters[0].name]).width + 20 + 12 + 6, itemHeight / 2 + itemY);
            ctx.moveTo(58 + 18 + ctx.measureText(item[0][dataParameters[0].name]).width + 20 + 7, itemHeight / 2 + itemY);
            let h = 0;
            let textLength = elem.sec_name.length * 10 + 25 + elem.org.length * 10 + 6 + 10 * 8 * 2;
            let textX = 58 + 18 + ctx.measureText(item[0][dataParameters[0].name]).width + 20 + 12 + 35;
            // 偶数
            if (even) {
              if (j < half) {
                h = (half - 1 - j) * (16 + 4 + 2 + 6) + 15;
                //ctx.lineTo(textX, itemHeight / 2 + itemY - h);
                ctx.bezierCurveTo(58 + 18 + ctx.measureText(item[0][dataParameters[0].name]).width + 20 + 7 + 20, itemHeight / 2 + itemY, textX - 20, itemHeight / 2 + itemY - h, textX, itemHeight / 2 + itemY - h);
                ctx.lineTo(textX + textLength, itemHeight / 2 + itemY - h);
                ctx.stroke();
                ctx.fillText(elem[dataParameters[1].name], textX + 15, itemHeight / 2 + itemY - h - 6)
                let diffX = textX + 15 + ctx.measureText(elem[dataParameters[1].name]).width + 20
                ctx.fillText(elem[dataParameters[2].name], diffX, itemHeight / 2 + itemY - h - 6)
                diffX = diffX + ctx.measureText(elem[dataParameters[2].name]).width + 10
                ctx.fillText(dataParameters[3].alias_name + elem[dataParameters[3].name] + '万' + ' ' + dataParameters[4].alias_name + elem[dataParameters[4].name] + '万', diffX, itemHeight / 2 + itemY - h - 6)
              } else {
                h = (j - half) * (16 + 4 + 2 + 6) + 15;
                //ctx.lineTo(textX, itemHeight / 2 + itemY + h);
                ctx.bezierCurveTo(58 + 18 + ctx.measureText(item[0][dataParameters[0].name]).width + 20 + 7 + 20, itemHeight / 2 + itemY, textX - 20, itemHeight / 2 + itemY + h, textX, itemHeight / 2 + itemY + h);
                ctx.lineTo(textX + textLength, itemHeight / 2 + itemY + h);
                ctx.stroke();
                ctx.fillText(elem[dataParameters[1].name], textX + 15, itemHeight / 2 + itemY + h - 6)
                let diffX = textX + 15 + ctx.measureText(elem[dataParameters[1].name]).width + 20
                ctx.fillText(elem[dataParameters[2].name], diffX, itemHeight / 2 + itemY + h - 6)
                diffX = diffX + ctx.measureText(elem[dataParameters[2].name]).width + 10
                ctx.fillText(dataParameters[3].alias_name + elem[dataParameters[3].name] + '万' + ' ' + dataParameters[4].alias_name + elem[dataParameters[4].name] + '万', diffX, itemHeight / 2 + itemY + h - 6)
              }
            } else {
              if (j < half) {
                h = (half - j) * (10 + 4 + 2 + 15);
                //ctx.lineTo(textX, itemHeight / 2 + itemY - h);
                ctx.bezierCurveTo(58 + 18 + ctx.measureText(item[0][dataParameters[0].name]).width + 20 + 7 + 20, itemHeight / 2 + itemY, textX - 20, itemHeight / 2 + itemY - h, textX, itemHeight / 2 + itemY - h);
                ctx.lineTo(textX + textLength, itemHeight / 2 + itemY - h);
                ctx.stroke();
                ctx.fillText(elem[dataParameters[1].name], textX + 15, itemHeight / 2 + itemY - h - 6)
                let diffX = textX + 15 + ctx.measureText(elem[dataParameters[1].name]).width + 20
                ctx.fillText(elem[dataParameters[2].name], diffX, itemHeight / 2 + itemY - h - 6)
                diffX = diffX + ctx.measureText(elem[dataParameters[2].name]).width + 10
                ctx.fillText(dataParameters[3].alias_name + elem[dataParameters[3].name] + '万' + ' ' + dataParameters[4].alias_name + elem[dataParameters[4].name] + '万', diffX, itemHeight / 2 + itemY - h - 6)
              } else {
                h = (j - half) * (10 + 4 + 2 + 15);
                //ctx.lineTo(textX, itemHeight / 2 + itemY + h);
                ctx.bezierCurveTo(58 + 18 + ctx.measureText(item[0][dataParameters[0].name]).width + 20 + 7 + 20, itemHeight / 2 + itemY, textX - 20, itemHeight / 2 + itemY + h, textX, itemHeight / 2 + itemY + h);
                ctx.lineTo(textX + textLength, itemHeight / 2 + itemY + h);
                ctx.stroke();
                ctx.fillText(elem[dataParameters[1].name], textX + 15, itemHeight / 2 + itemY + h - 6)
                let diffX = textX + 15 + ctx.measureText(elem[dataParameters[1].name]).width + 20
                ctx.fillText(elem[dataParameters[2].name], diffX, itemHeight / 2 + itemY + h - 6)
                diffX = diffX + ctx.measureText(elem[dataParameters[2].name]).width + 10
                ctx.fillText(dataParameters[3].alias_name + elem[dataParameters[3].name] + '万' + ' ' + dataParameters[4].alias_name + elem[dataParameters[4].name] + '万', diffX, itemHeight / 2 + itemY + h - 6)
              }

            }
            ctx.restore();
          }
          itemY += itemHeight;
        }
      }
      ctx.beginPath();
      ctx.moveTo(58, firstItemMiddleHeight);
      ctx.lineTo(58, lastItemMiddleHeight);
      ctx.stroke();
    }
  }
  pipePngImage(path) {
    const out = fs.createWriteStream(path)
    const stream = this.canvas.createPNGStream()
    stream.pipe(out)
    out.on('finish', () => console.log('The PNG file was created.'))
  }
  pipeBase64Image() {
    return this.canvas.toDataURL();
  }
}


module.exports = Treechart;